/*	
*	File: ethernet-header.h
*	Date: 2011/11/26
*	User: Ronmaru
*	Desctiption: ethernet header class
*/

#ifndef _ETHERNET_PACKET_H
#define _ETHERNET_PACKET_H

#include <istream>
#include <ostream>
#include <algorithm>
#include "mac-address-type.h"

// Ethernet header 
//
// The wire format of an Ethernet header is:
// 0                 5                 11    13
// +-----------------+-----------------+-----+
// |destination mac  |source mac       |type |
// |XX:XX:XX:XX:XX:XX|YY:YY:YY:YY:YY:YY|ZZ:ZZ|
// +-----------------+-----------------+-----+

const int ETHERNET_MAX_HEADER_LENGTH = 14;

class ETHERNETheader
{
public:
  ETHERNETheader() { std::fill(rep_, rep_ + sizeof(rep_), 0); }

  void SetDestinationMac(const MacAddress &mac_address) { 
    for (int i = 0; i < mac_address.size(); ++i) {
      rep_[0 + i] = mac_address[i];
    }
  }
  void SetSourceMac(const MacAddress &mac_address) { 
    for (int i = 0; i < mac_address.size(); ++i) {
      rep_[6 + i] = mac_address[i];
    }
  }
  void SetType(unsigned short n) { Encode(12, 13, n); }

  MacAddress GetDestinationMac() const { 
    MacAddress mac_address;
    for (int i = 0; i < 6; ++i) {
      mac_address.push_back(rep_[0 + i]);
    }
    return mac_address;
  }
  MacAddress GetSourceMac() const { 
    MacAddress mac_address;
    for (int i = 0; i < 6; ++i) {
      mac_address.push_back(rep_[6 + i]);
    }
    return mac_address;
  }
  unsigned short GetType() const { return Decode(12, 13); }

  friend std::istream& operator>>(std::istream& is, ETHERNETheader& header)
  { return is.read(reinterpret_cast<char*>(header.rep_), ETHERNET_MAX_HEADER_LENGTH); }

  friend std::ostream& operator<<(std::ostream& os, const ETHERNETheader& header)
  { return os.write(reinterpret_cast<const char*>(header.rep_), ETHERNET_MAX_HEADER_LENGTH); }

private:
  unsigned short Decode(int a, int b) const
  { return (rep_[a] << 8) + rep_[b]; }

  void Encode(int a, int b, unsigned short n)
  {
    rep_[a] = static_cast<unsigned char>(n >> 8);
    rep_[b] = static_cast<unsigned char>(n & 0xFF);
  }

  unsigned char rep_[ETHERNET_MAX_HEADER_LENGTH];
};

#endif //_ETHERNET_PACKET_H